#ifndef __DS_SPACE__
#define __DS_SPACE__

#include <map>

#include <bullet/btBulletCollisionCommon.h>
#include <bullet/btBulletDynamicsCommon.h>

#include "BulletUtils.hpp"
#include "SpaceObject.hpp"
#include "Ship.hpp"

namespace ds {

class Space {
private:
    btBroadphaseInterface*                  broadphase;
    btDefaultCollisionConfiguration*        collisionConfiguration;
    btCollisionDispatcher*                  dispatcher;
    btSequentialImpulseConstraintSolver*    solver;
    btDiscreteDynamicsWorld*                dynamicsWorld;

    std::map<std::string, boost::shared_ptr<Ship> > ships;

public:
    Space() {
        this->broadphase = new btDbvtBroadphase();
        this->collisionConfiguration = new btDefaultCollisionConfiguration();
        this->dispatcher = new btCollisionDispatcher(this->collisionConfiguration);
        this->solver = new btSequentialImpulseConstraintSolver;
        this->dynamicsWorld = new btDiscreteDynamicsWorld(this->dispatcher, this->broadphase, this->solver, this->collisionConfiguration);

        this->dynamicsWorld->setGravity(btVector3(0.0, 0.0, 0.0));
    }

    ~Space() {
        delete this->dynamicsWorld;
        delete this->solver;
        delete this->dispatcher;
        delete this->collisionConfiguration;
        delete this->broadphase;
    }

    inline void update(int clock) {
        dynamicsWorld->stepSimulation(clock/1000.0f, 10);
        dynamicsWorld->clearForces();
        for (std::map<std::string, boost::shared_ptr<Ship> >::iterator i = ships.begin(); i != ships.end(); i++)
            i->second->update(clock);
    }

    inline void draw() {
        for (std::map<std::string, boost::shared_ptr<Ship> >::iterator i = ships.begin(); i != ships.end(); i++)
            i->second->draw();
    }

    inline boost::shared_ptr<Ship> addShip(const std::string &specifics, const ShipConfiguration &config) {
        ds::Ship* ship = new ds::Ship(specifics, config.view);
        if (ship->isLoaded()) {
            std::string tmps;
            if (config.id == "")
                tmps = "ship_" + boost::lexical_cast<std::string>(ships.size());
            else
                tmps = config.id;
            ship->name = config.name;
            boost::shared_ptr<Ship> ship_ptr(ship);
            ships.insert(std::pair<std::string, boost::shared_ptr<Ship> >(tmps, ship_ptr));
            dynamicsWorld->addRigidBody(ship->getBody());
            return ship_ptr;
        }
        delete ship;
        return boost::shared_ptr<Ship>();
    }
};

} // namespace ds

#endif
